package com.atguigu.gmall.product.service.impl;


import com.atguigu.gmall.common.cache.GmallCache;
import com.atguigu.gmall.common.constant.RedisConst;
import com.atguigu.gmall.model.product.*;
import com.atguigu.gmall.product.mapper.*;
import com.atguigu.gmall.product.service.ManagerService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.util.*;

import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Service
public class ManageServiceImpl implements ManagerService {

    @Autowired
    private BaseCategory1Mapper baseCategory1Mapper;
    @Autowired
    private BaseCategory2Mapper baseCategory2Mapper;
    @Autowired
    private BaseCategory3Mapper baseCategory3Mapper;
    @Autowired
    private BaseAttrInfoMapper baseAttrInfoMapper;
    @Autowired
    private BaseAttrValueMapper baseAttrValueMapper;
    @Autowired
    private BaseTrademarkMapper baseTrademarkMapper;

    //获取一级分类
    @Override
    public List<BaseCategory1> getCategory1() {

        //查询所有一级分类
        return baseCategory1Mapper.selectList(null);
    }

    //获取二级分类id
    @Override
    public List<BaseCategory2> getCategory2(Long category1Id) {

        return baseCategory2Mapper.selectList(new QueryWrapper<BaseCategory2>()
                .eq("category1_id", category1Id));
    }

    @Override
    public List<BaseCategory3> getCategory3(Long category2Id) {

        return baseCategory3Mapper.selectList(new QueryWrapper<BaseCategory3>().eq("category2_id", category2Id));
    }

    //根据分类id获取平台属性
    @Override
    public List<BaseAttrInfo> attrInfoList(Long category1Id, Long category2Id, Long category3Id) {
        //mapper.xml文件解决

        return baseAttrInfoMapper.attrInfoList(category1Id, category2Id, category3Id);
    }

    //保存平台属性,属性值
    @Override
    public void saveAttrInfo(BaseAttrInfo baseAttrInfo) {
        //1.保存平台属性
        baseAttrInfoMapper.insert(baseAttrInfo);
        //2.保存平台属性值
        List<BaseAttrValue> attrValueList = baseAttrInfo.getAttrValueList();
        if (!CollectionUtils.isEmpty(attrValueList)) {
            attrValueList.forEach(attrValue -> {
                //平台属性值表的ID作为外键
                attrValue.setAttrId(baseAttrInfo.getId());
                baseAttrValueMapper.insert(attrValue);
            });

        }
    }

    //查询品牌集合,分页查询
    @Override
    public IPage<BaseTrademark> baseTrademark(Integer page, Integer limit) {

        Page<BaseTrademark> p = new Page<>(page, limit);
        IPage<BaseTrademark> baseTrademarkIPage = baseTrademarkMapper.selectPage(p, null);
        return baseTrademarkIPage;
    }

    @Autowired
    private SpuInfoMapper spuInfoMapper;

    //获取spu分页列表,根据三级分类id
    @Override
    public IPage<SpuInfo> spuPage(Integer page, Integer limit, Long category3Id) {
        Page<SpuInfo> p = new Page<>(page, limit);
        IPage<SpuInfo> spuInfoIPage = spuInfoMapper.
                selectPage(p, new QueryWrapper<SpuInfo>().eq("category3_id", category3Id));
        return spuInfoIPage;
    }

    //查询所有品牌的集合
    @Override
    public List<BaseTrademark> getTrademarkList() {

        List<BaseTrademark> baseTrademarkList = baseTrademarkMapper.selectList(null);
        return baseTrademarkList;
    }

    @Autowired
    private BaseSaleAttrMapper baseSaleAttrMapper;

    //获取所有销售属性
    @Override
    public List<BaseSaleAttr> baseSaleAttrList() {

        return baseSaleAttrMapper.selectList(null);
    }


    @Autowired
    private SpuImageMapper spuImageMapper;
    @Autowired
    private SpuSaleAttrMapper spuSaleAttrMapper;
    @Autowired
    private SpuSaleAttrValueMapper spuSaleAttrValueMapper;

    //保存商品信息
    @Override
    public void saveSpuInfo(SpuInfo spuInfo) {
        //1.保存Spu_info 商品信息表
        spuInfoMapper.insert(spuInfo);
        //2.商品图片表
        List<SpuImage> spuImageList = spuInfo.getSpuImageList();
        spuImageList.forEach(image -> {
            //商品信息表的id做为外键
            image.setSpuId(spuInfo.getId());
            spuImageMapper.insert(image);
        });
        //3.商品销售属性
        List<SpuSaleAttr> spuSaleAttrList = spuInfo.getSpuSaleAttrList();
        spuSaleAttrList.forEach(saleAttr -> {
            //设置外键
            saleAttr.setSpuId(spuInfo.getId());
            spuSaleAttrMapper.insert(saleAttr);
            //销售属性 -- 多个销售属性值
            List<SpuSaleAttrValue> spuSaleAttrValueList = saleAttr.getSpuSaleAttrValueList();
            spuSaleAttrValueList.forEach(saleAttrValue -> {
                saleAttrValue.setSpuId(spuInfo.getId());
                spuSaleAttrValueMapper.insert(saleAttrValue);
            });
        });

    }

    //根据spuId获取图片列表
    @Override
    public List<SpuImage> spuImageList(Long spuId) {

        return spuImageMapper.selectList(
                new QueryWrapper<SpuImage>().eq("spu_id", spuId));
    }

    //根据spuId 查询销售属性及嵌套的属性值集合
    @Override
    public List<SpuSaleAttr> spuSaleAttrList(Long spuId) {
        //现在需要关联查询,使用mapper.xml
        List<SpuSaleAttr> spuSaleAttrList = spuSaleAttrMapper.spuSaleAttrList(spuId);
        return spuSaleAttrList;
    }


    @Autowired
    private SkuInfoMapper skuInfoMapper;
    @Autowired
    private SkuImageMapper skuImageMapper;
    @Autowired
    private SkuSaleAttrValueMapper skuSaleAttrValueMapper;
    @Autowired
    private SkuAttrValueMapper skuAttrValueMapper;

    //保存Sku 四张表
    @Override
    public void saveSkuInfo(SkuInfo skuInfo) {
        //默认不是卖
        skuInfo.setIsSale(0);
        //1.sku_info
        skuInfoMapper.insert(skuInfo);
        //2.sku_image
        List<SkuImage> skuImageList = skuInfo.getSkuImageList();
        skuImageList.forEach(image -> {
            //外键
            image.setSkuId(skuInfo.getId());
            skuImageMapper.insert(image);
        });
        //3.销售属性 sku_sale_attr_value
        List<SkuSaleAttrValue> skuSaleAttrValueList = skuInfo.getSkuSaleAttrValueList();
        skuSaleAttrValueList.forEach(skuSaleAttrValue -> {
            //外键 sku_id
            skuSaleAttrValue.setSkuId(skuInfo.getId());
            //外键 spu_id
            skuSaleAttrValue.setSpuId(skuInfo.getSpuId());
            skuSaleAttrValueMapper.insert(skuSaleAttrValue);
        });

        //4.平台属性 sku_attr_value
        List<SkuAttrValue> skuAttrValueList = skuInfo.getSkuAttrValueList();
        skuAttrValueList.forEach(skuAttrValue -> {
            //外键
            skuAttrValue.setSkuId(skuInfo.getId());
            skuAttrValueMapper.insert(skuAttrValue);
        });
    }

    //查询Sku分页列表
    @Override
    public IPage<SkuInfo> skuList(Integer page, Integer limit) {

        return skuInfoMapper.selectPage(new Page<SkuInfo>(page, limit), null);
    }

    //上架
    @Override
    public void onSale(Long skuId) {
        //1.更新库存上下架状态
        SkuInfo skuInfo = new SkuInfo();
        skuInfo.setId(skuId);
        skuInfo.setIsSale(1);
        skuInfoMapper.updateById(skuInfo);
        //2.保存索引
        //TODO
    }

    //下架
    @Override
    public void cancelSale(Long skuId) {
        //1.更新库存上下架状态
        SkuInfo skuInfo = new SkuInfo();
        skuInfo.setId(skuId);
        skuInfo.setIsSale(0);
        skuInfoMapper.updateById(skuInfo);
        //2.删除索引
        //TODO
    }


    //####################################################################
    //前台
    //根据skuId 查询库存表
    /*@Override
    public SkuInfo getSkuInfo(Long skuId) {
        //根据skuId 查询库存表
        SkuInfo skuInfo = skuInfoMapper.selectById(skuId);
        //根据skuId 查询库存图片表
        List<SkuImage> skuImageList = skuImageMapper.selectList(new QueryWrapper<SkuImage>().eq("sku_id", skuId));
        skuInfo.setSkuImageList(skuImageList);
        return skuInfo;
    }*/

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private RedissonClient redissonClient;

    //使用redisson解决缓存出现的问题
    @Override
    public SkuInfo getSkuInfo(Long skuId) {
        //库存表保存在缓存中的Key的组成结构
        String key = RedisConst.SKUKEY_PREFIX + skuId + RedisConst.SKUKEY_SUFFIX;
        //1:从缓存中获取SkuInfo信息
        SkuInfo skuInfo = (SkuInfo) redisTemplate.opsForValue().get(key);
        if (null != skuInfo) {
            return skuInfo;
        } else {
            //上锁    缓存三大问题之一缓存击穿 百万请求只允许派一个代表来查询Mysql数据 其它不让进
            RLock lock = redissonClient.getLock(key + ":lock");
            try {
                boolean tryLock = lock.tryLock(1, 10, TimeUnit.SECONDS);
                //我是代表：我是第一人 拿到锁了
                if (tryLock) {
                    skuInfo = skuInfoMapper.selectById(skuId);
                    //缓存三大问题之一的穿透
                    if (null == skuInfo) {
                        //空结果也进行缓存
                        skuInfo = new SkuInfo();
                        redisTemplate.opsForValue().set(key, skuInfo, 5, TimeUnit.MINUTES);//设置过期时间
                        return skuInfo;
                    } else {
                        //查询Sku图片
                        List<SkuImage> skuImageList = skuImageMapper.
                                selectList(new QueryWrapper<SkuImage>().eq("sku_id", skuId));
                        skuInfo.setSkuImageList(skuImageList);
                        Random random = new Random();
                        int i = random.nextInt(300);//300以内随机数
                        redisTemplate.opsForValue().set(key, skuInfo, RedisConst.SKUKEY_TIMEOUT +i, TimeUnit.SECONDS);
                        return skuInfo;
                    }
                } else {
                    //我不是第一人 也不是代表
                    Thread.sleep(2000);//等你一会,代表应该可以执行完了吧
                    return (SkuInfo) redisTemplate.opsForValue().get(key);
                }

            } catch (Exception e) {
                e.printStackTrace();
            }finally {
                if (lock.isLocked()) {//判断 是自己的锁吗？
                    lock.unlock();
                }
            }
        }
        return getSkuInfoDBById(skuId);

    }
    //提取根据库存Id 查询Mysql数据库的SkuInfo
    public SkuInfo getSkuInfoDBById(Long skuId) {
        //此处也会出现穿透的情况：
        SkuInfo skuInfo = skuInfoMapper.selectById(skuId);
        if (null == skuInfo) {
            //在抛出异常时  会执行此处代码
            skuInfo = new SkuInfo();
            return skuInfo;
        }
        List<SkuImage> skuImageList = skuImageMapper.
                selectList(new QueryWrapper<SkuImage>().eq("sku_id", skuId));
        skuInfo.setSkuImageList(skuImageList);
        return skuInfo;

    }

    /*//初始版本
    @Override
    public SkuInfo getSkuInfo(Long skuId) {
        //1.先去redis中获取 //String Hash List偶尔
        String key = RedisConst.SKUKEY_PREFIX + skuId + RedisConst.SKUKEY_SUFFIX;

        SkuInfo skuInfo = (SkuInfo) redisTemplate.opsForValue().get(key);
        if (null != skuInfo) {
            System.out.println("缓存中已经有数据了：" + JSON.toJSONString(skuInfo));
            //2 有，直接返回
            return skuInfo;
        } else {
            System.out.println("缓存中没有数据");
            //3.没有 去mysql数据库中查询
            //3.1根据skuId 查询库存表
            skuInfo = skuInfoMapper.selectById(skuId);
            //判断获取Mysql数据中SkuInfo是否为NULL  为NULL表示人为攻击 返回空结果
            if (null ==skuInfo) {
                skuInfo = new SkuInfo();
                System.out.println("有人攻击我们网站：skuId不存在：返回空结果");
                redisTemplate.opsForValue().set(key,skuInfo,5, TimeUnit.MINUTES);//时间5分钟
                return skuInfo;
            }
            //3.2根据skuId 查询库存图片表
            List<SkuImage> skuImageList = skuImageMapper.selectList(new QueryWrapper<SkuImage>().eq("sku_id", skuId));
            skuInfo.setSkuImageList(skuImageList);
            System.out.println("缓存中再次保存了一份数据：" + JSON.toJSONString(skuInfo));


            //随机数
            Random random = new Random();
            int i = random.nextInt(300);//300以内随机数

            //4.在保存缓存中一份
            redisTemplate.opsForValue().set(key, skuInfo,RedisConst.SKUKEY_TIMEOUT + i,TimeUnit.SECONDS);
            //5.返回

            return skuInfo;
        }
    }*/

    @Autowired
    private BaseCategoryViewMapper baseCategoryViewMapper;

    //根据三级分类的ID 查询一二三级分类的ID、名称
    @Override
    @GmallCache(prefix = "getBaseCategoryView")
    public BaseCategoryView getBaseCategoryView(Long category3Id) {
        return baseCategoryViewMapper.selectById(category3Id);
    }

    //单独查询价格
    @Override
    public BigDecimal getPrice(Long skuId) {

        SkuInfo skuInfo = skuInfoMapper.selectById(skuId);
        if (null != skuInfo) {//防止null空指针异常
            return skuInfo.getPrice();
        } else {
            return null;
        }
    }

    //4.根据商品ID 查询销售属性及销售属性值集合
    //并且根据当前skuId库存ID查询出对应的销售属性值
    @Override
    public List<SpuSaleAttr> getSpuSaleAttrListCheckBySku(Long skuId, Long spuId) {
        return spuSaleAttrMapper.getSpuSaleAttrListCheckBySku(skuId, spuId);
    }

    //5.查询组合对应库存ID
    //“属性值1|属性值2|属性值3：skuId”的一个json串以提供页面进行匹配
    @Override
    public Map getSkuValueIdsMap(Long spuId) {
        Map result = new HashMap();
        List<Map> skuValueIdsMap = skuSaleAttrValueMapper.getSkuValueIdsMap(spuId);
        //Map1 K:values_id V:11|22|33  K:sku_id V:10
        skuValueIdsMap.forEach(map -> {
            result.put(map.get("values_id"), map.get("sku_id"));
        });

        return result;
    }

    //查询分类视图对象集合 （查询全部）
    @Override
    public List<Map> getBaseCategoryList() {

        //结果对象
        List<Map> result = new ArrayList<>();
        List<BaseCategoryView> baseCategoryViews = baseCategoryViewMapper.
                selectList(null);

        Map<Long, List<BaseCategoryView>> baseCategoryViewByCategory1Id =
                baseCategoryViews.
                stream().
                collect(Collectors.groupingBy(BaseCategoryView::getCategory1Id));
        //Map1 k: 1 V:List<BaseCategoryView>  60  ID:1-60
        //Map2 k: 2 V:List<BaseCategoryView>  24 ID:61-85
        //定义角标
        int index = 1;
        for (Map.Entry<Long, List<BaseCategoryView>> category1IdEntry :
                baseCategoryViewByCategory1Id.entrySet()) {
            Map category1IdMap = new HashMap();
            //1.角标
            category1IdMap.put("index", index++);
            //2.一级分类的ID
            category1IdMap.put("categoryId", category1IdEntry.getKey());
            //3.一级分类的名称
            category1IdMap.put("categoryName", category1IdEntry.getValue().get(0).getCategory1Name());
            //4.二级分类的集合，子节点
            //4-1 二级分类的集合
            Map<Long, List<BaseCategoryView>> baseCategoryViewByCategory2Id =
                    category1IdEntry.
                    getValue().
                    stream().
                    collect(Collectors.groupingBy(BaseCategoryView::getCategory2Id));
            //Map1 K:二级分类的id v: 长度是4
            List<Map> result2 = new ArrayList<>();
            for (Map.Entry<Long, List<BaseCategoryView>> category2IdEntry : baseCategoryViewByCategory2Id.entrySet()) {
                Map category2IdMap = new HashMap();

                List<BaseCategoryView> category3IdValue = category2IdEntry.getValue();

                //1.二级分类的id
                category2IdMap.put("categoryId", category2IdEntry.getKey());
                //2.二级分类的name
                category2IdMap.put("categoryName", category3IdValue.get(0).getCategory2Name());

                //3.三级分类的集合
                //4-1-3
                List<Map> result3 = new ArrayList<>();
                for (BaseCategoryView baseCategoryView : category3IdValue) {
                    Map category3IdMap = new HashMap();
                    //1.三级分类的id
                    category3IdMap.put("categoryId", baseCategoryView.getCategory3Id());
                    //2.三级分类的name
                    category3IdMap.put("categoryName",baseCategoryView.getCategory3Name());
                    result3.add(category3IdMap);
                }

                category2IdMap.put("categoryChild",result3 );//"三级分类的集合"
                result2.add(category2IdMap);
            }
            category1IdMap.put("categoryChild",result2 );//"二级分类的集合"

            result.add(category1IdMap);

        }

        return result;
    }

    //对外暴露品牌
    @Override
    public BaseTrademark getTrademarkByTmId(Long tmId) {

        return baseTrademarkMapper.selectById(tmId);
    }

    //根据skuId 查询 平台属性ID、属性名称、及平台属性值
    @Override
    public List<SkuAttrValue> getSkuAttrValueList(Long skuId) {

        return skuAttrValueMapper.getSkuAttrValueList(skuId);
    }

}
